﻿using GameCreator.Camera;
using GameCreator.Characters;
using GameCreator.Core;
using GameCreator.Core.Hooks;
using Gp.Input;
using Gp.Scripts.Core;
using Helpers;
using UnityEngine;

namespace Gp.Scripts.Character {
    public class PlayerBaseCharacter : BaseCharacter {
        protected const string PLAYER_ID = PlayerConst.PlayerName;
        public static OnLoadSceneData ON_LOAD_SCENE_DATA;
        public Vector3 directionVelocity = Vector3.zero;

        public bool useAcceleration = true;
        public float acceleration = 5f;
        public float deceleration = 300f;

        private Transform _sensor;

        public bool EnableFallenFix { get; set; }

        protected override void Awake() {
            if (!Application.isPlaying) return;
            this.CharacterAwake();

            this.initSaveData = new SaveData() {
                position = transform.position,
                rotation = transform.rotation,
            };

            if (this.save) {
                SaveLoadManager.Instance.Initialize(
                    this, (int) SaveLoadManager.Priority.Normal, true
                );
            }

            HookPlayer hookPlayer = gameObject.GetComponent<HookPlayer>();
            if (hookPlayer == null) gameObject.AddComponent<HookPlayer>();


            _sensor = new GameObject("Sensor").transform;
            _sensor.transform.SetParent(transform, false);
            _sensor.localPosition = Vector3.forward;

            if (ON_LOAD_SCENE_DATA is not {active: true}) return;


            transform.position = ON_LOAD_SCENE_DATA.position;
            transform.rotation = ON_LOAD_SCENE_DATA.rotation;
            ON_LOAD_SCENE_DATA.Consume();
        }


        private bool _isRunning;
        private bool _isTargetMoving = false;
        private bool _isMouseDirectionLock = false;


        protected override void Update() {
            if (!Application.isPlaying) return;
            _isMouseDirectionLock = Global.Get<InputManager>().IsMousePressing(MouseButtonCode.MouseRightButton);

            characterLocomotion.forceWalk = _isMouseDirectionLock;
            Global.GetSceneRoot<PlayerRoot>().CameraFlowPivot.SetFocusMode(_isMouseDirectionLock);


            if (_isMouseDirectionLock) {
                Vector2 mousePosition = Global.Get<InputManager>().MousePosition();
                Vector2 playerScreenPos = ObjectHelper.MainCamera.WorldToScreenPoint(transform.position);
                Vector2 normalied = (playerScreenPos - mousePosition).normalized;
                var targetDirection = new Vector3(normalied.x, 0f, normalied.y);
                float y = ObjectHelper.MainCamera.transform.rotation.eulerAngles.y;
                targetDirection = Quaternion.Euler(0f, y - 180f, 0f) * targetDirection;
                
                var lookAtPos = targetDirection + transform.position;

                characterLocomotion.faceDirection = CharacterLocomotion.FACE_DIRECTION.Target;
                characterLocomotion.faceDirectionTarget.targetPosition = lookAtPos;
                characterLocomotion.faceDirectionTarget.target = TargetPosition.Target.Position;

                GetCharacterAnimator().useSmartHeadIK = false;
            }
            else
            {
                GetCharacterAnimator().useSmartHeadIK = true;
                characterLocomotion.faceDirection = CharacterLocomotion.FACE_DIRECTION.MovementDirection;
            }

            UpdateInputDirectional();

            if (!IsControllable()) {
                direction = Vector3.zero;
            }


            this.CharacterUpdate();
        }


        private const float CharacterOrgSpeed = 5.5f;


        public void SetRunSpeed(int level) {
            level = Mathf.Clamp(level, 1, 3);
            characterLocomotion.runSpeed = CharacterOrgSpeed * level;
        }

        // public bool PathCheck() {
        //     return true;
        //     // if (!EnableFallenFix) return true;
        //     //
        //     // var position = _sensor.transform.position;
        //     // return NavMesh.SamplePosition(position, out var hit, 1f, NavMesh.AllAreas);
        // }

        private float _timeCount = 0;
        protected virtual void UpdateInputDirectional() {
            var input = Global.Get<InputManager>().PlayerMovement();
            var target = new Vector3(
                input.x,
                0.0f,
                input.y
            );

            if (!IsControllable()) return;

            if (Mathf.Abs(input.magnitude) < .1f) _timeCount += Time.deltaTime;
            else _timeCount = 0;
            if (_timeCount > .2f) characterLocomotion.canRun = false;

            
            // 奔跑
            if (Global.Get<InputManager>().InputAction.City.Run.WasPressedThisFrame())
                characterLocomotion.canRun = !characterLocomotion.canRun;

            Camera cam = this.GetMainCamera();
            if (cam == null) return;

            this.direction = ComputeMovement(target);


            Vector3 moveDirection = (
                Quaternion.Euler(0, cam.transform.rotation.eulerAngles.y, 0) *
                this.direction
            );
            this.characterLocomotion.SetDirectionalDirection(moveDirection);
        }


        //
        // private RaycastHit[] _hitBuffer = new RaycastHit[5];
        // protected virtual void UpdateInputPointClick() {
        //     if (!this.IsControllable()) return;
        //
        //     if (!CursorManageSystem.Instance.Ray(out var ray) || CursorManageSystem.IsPointerOverUIObject()) {
        //         return;
        //     }
        //     
        //     
        //     QueryTriggerInteraction queryTrigger = QueryTriggerInteraction.Ignore;
        //     int hitCount = Physics.RaycastNonAlloc(
        //         ray, this._hitBuffer, Mathf.Infinity,
        //         CursorManageSystem.Instance.DefaultLayer, queryTrigger
        //     );
        //
        //     // 筛除Hidable
        //     for (int i = 0; i < hitCount; i++) {
        //         if (_hitBuffer[i].collider.CompareTag("Hidable")) continue;
        //         _isTargetMoving = true;
        //         characterLocomotion.SetTarget(_hitBuffer[i].point, null, .5f, () => _isTargetMoving = false);
        //         break;
        //     } 
        // }
        //


        protected Vector3 ComputeMovement(Vector3 target) {
            if (Mathf.Approximately(target.sqrMagnitude, 0f))
            {
                // todo: 设置动画参数，判断是否播放急停动画
                return Vector3.zero;
            }
            
            float acc = acceleration;

            var res = Vector3.SmoothDamp(
                this.direction, target,
                ref this.directionVelocity,
                1f / acc,
                acc
            );

            if (Mathf.Abs(target.sqrMagnitude) < 0.1f && Mathf.Abs(this.direction.sqrMagnitude) < 0.1f) {
                res = Vector3.zero;
            }

            return res;
        }


        // GAME SAVE: -----------------------------------------------------------------------------
        protected override string GetUniqueCharacterID() {
            return PLAYER_ID;
        }
    }
}